﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using UIT.Markup;
using System.Xml;
using System.ComponentModel;
using System.Windows.Markup;
using System.Text;
using UIT.Controls;

namespace UIT.Sl.Xaml
{
	public class XamlXmlWriter
	{
		private static void WriteProperty(XmlWriter writer, object target, PropertyInfo property)
		{
			writer.WriteAttributeString(property.Name, new TypeConverter().ConvertToString(property.GetValue(target, null)));
		}

		private static void WriteProperty(XmlWriter writer, IBindingContainer target, PropertyInfo property)
		{
			Binding binding = target.GetBinding(property.Name);
			writer.WriteAttributeString(property.Name, binding.ToString());
		}

		public static string WriteObject(object target)
		{
			StringBuilder sb = new StringBuilder();
			XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { NamespaceHandling = NamespaceHandling.OmitDuplicates, OmitXmlDeclaration = true });
			Attribute[] xmlnsAttributes = Attribute.GetCustomAttributes(target.GetType().Assembly, typeof(XmlnsDefinitionAttribute));
			Attribute[] prefixAttributes = Attribute.GetCustomAttributes(target.GetType().Assembly, typeof(XmlnsPrefixAttribute));
			bool isFirst = true;
			foreach (string ns in XamlCacheWriter.FindNeededNamespaces(target))
			{
				if (xmlnsAttributes.Length == 0)
					writer.WriteStartElement(target.GetType().Name);
				for (int i = 0; i < xmlnsAttributes.Length; i++)
				{
					XmlnsDefinitionAttribute xmlns = (XmlnsDefinitionAttribute)xmlnsAttributes[i];
					if (ns == xmlns.ClrNamespace)
					{
						if (isFirst)
						{
							writer.WriteStartElement(target.GetType().Name, xmlns.XmlNamespace);
							isFirst = false;
						}
						else
						{
							XmlnsPrefixAttribute prefix = null;
							for (int j = 0; j < prefixAttributes.Length; j++)
							{
								if (((XmlnsPrefixAttribute)prefixAttributes[i]).XmlNamespace == xmlns.XmlNamespace)
								{
									prefix = (XmlnsPrefixAttribute)prefixAttributes[j];
								}
							}
							if (prefix != null)
								writer.WriteAttributeString("xmlns", prefix.Prefix, xmlns.XmlNamespace);
							else
							{
								if (writer.LookupPrefix(xmlns.XmlNamespace) == null)
									writer.WriteAttributeString("xmlns", "ns" + i, xmlns.XmlNamespace);
							}
						}
					}
				}
			}
			WriteObjectContent(writer, target);

			writer.WriteEndElement();
			writer.Flush();
			return sb.ToString();
		}

		private static void WriteObjectContent(XmlWriter writer, object target)
		{
			var accessors = XamlCacheWriter.GetCachedAccessors(target.GetType());
			foreach (CacheAccessor accessor in accessors)
			{
				object result = accessor.Invoke(target);
				if (result == null)
					continue;
				if (XamlCacheWriter.WriteAsAttribute(result))
				{
					string stringResult = result.ToString();
					if (!string.IsNullOrEmpty(stringResult))
						writer.WriteAttributeString(accessor.Name, stringResult);
				}
			}
			foreach (CacheAccessor accessor in accessors)
			{
				object result = accessor.Invoke(target);
				if (result == null)
					continue;
				if (!XamlCacheWriter.WriteAsAttribute(result))
				{
					writer.WriteStartElement(target.GetType().Name + "." + accessor.Name);
					WriteObjectContent(writer, result);
					writer.WriteEndElement();
				}
			}
		}
	}
}
